package com.lambkit.core.flow;

import com.lambkit.core.LifecycleException;
import com.lambkit.core.LifecycleState;
import com.lambkit.util.Printer;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yangyong(孤竹行)
 */
public abstract class BaseFlowNode implements IFlowNode {

    private LifecycleState currentState = LifecycleState.NEW;

    private String id;
    //前序规则
    private IFlowNodePreRule preRule;
    //后序规则
    private IFlowNodeNextRule nextRule;
    //前序节点
    private List<IFlowNode> preNodes;
    //后序节点
    private List<IFlowNode> nextNodes;
    //流程
    private FlowInstance flowInstance;
    //节点对象
    private FlowNodeObject flowNodeObject;

    public BaseFlowNode(FlowNodeObject flowNodeObject, FlowInstance flowInstance)  {
        this.id = flowNodeObject.getCode();
        this.flowNodeObject = flowNodeObject;
        this.flowInstance = flowInstance;
        for(String nextCode : flowNodeObject.getNext()) {
            FlowNodeObject nodeObject = flowInstance.getFlowContext().getInstanceObject().getNode(nextCode);
            IFlowNode flowNode = flowInstance.getAppContext()
                    .getFlowWorkCenter().getFlowNodeFactory().get(nodeObject, flowInstance);
            this.addNextNode(flowNode);
        }
    }

    @Override
    public LifecycleState getCurrentState() {
        return currentState;
    }

    public void setCurrentState(LifecycleState currentState) {
        this.currentState = currentState;
    }

    public boolean isInitStatus() {
        return getFlowNodeObject().getStatus().equals(FlowConsts.FLOW_STATUS_INIT) ? true : false;
    }

    public boolean isStartStatus() {
        return getFlowNodeObject().getStatus().equals(FlowConsts.FLOW_STATUS_START) ? true : false;
    }
    @Override
    public void start() throws LifecycleException {
        Printer.print(this, "flow", "start node:" + getId());
        if(this.currentState == LifecycleState.NEW) {
            this.currentState = LifecycleState.STARTING;
        }
        if(this.currentState != LifecycleState.STARTING) {
            return;
        }
        //启动定时任务，判断前序节点是否完成
        if(isInitStatus() && preRule != null) {
            boolean flag = preRule.check(this);
            if(!flag) {
                //加入到FlowInstance中，进行监听
                flowInstance.add(this);
                return;
            }
        }
        if(this.currentState != LifecycleState.STARTING) {
            return;
        }
        this.currentState = LifecycleState.STARTED;
        getFlowNodeObject().setStatus("start");
        //处理本节点事务
        execute(flowInstance.getFlowContext());
    }

    @Override
    public void stop() throws LifecycleException {
        this.currentState = LifecycleState.STOPPING;
        Printer.print(this, "flow", "stop node:" + getId());
        //处理完成，启动下一个节点
        if(nextRule != null) {
            List<IFlowNode> nodes = nextRule.decision(this, flowInstance.getFlowContext());
            if(nodes != null && nodes.size() > 0) {
                for(IFlowNode node : nodes) {
                    //加入到FlowInstance中，进行监听
                    flowInstance.add(node);
                }
            }
        } else {
            if(this.nextNodes != null && nextNodes.size() > 0) {
                for(IFlowNode node : nextNodes) {
                    //加入到FlowInstance中，进行监听
                    flowInstance.add(node);
                }
            }
        }
        getFlowNodeObject().setStatus("stop");
        this.currentState = LifecycleState.STOPPED;
    }

    @Override
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public BaseFlowNode addNextNode(IFlowNode node) {
        BaseFlowNode flowNode = (BaseFlowNode) node;
        if(nextNodes == null) {
            nextNodes = new ArrayList<>();
        }
        nextNodes.add(node);
        flowNode.addPreNode(this);
        return this;
    }
    protected void addPreNode(IFlowNode node) {
        if(preNodes == null) {
            preNodes = new ArrayList<>();
        }
        preNodes.add(node);
    }

    @Override
    public IFlowNodePreRule getPreRule() {
        return preRule;
    }

    @Override
    public IFlowNodeNextRule getNextRule() {
        return nextRule;
    }

    @Override
    public List<IFlowNode> getPreNode() {
        return preNodes;
    }

    @Override
    public List<IFlowNode> getNextNode() {
        return nextNodes;
    }

    public void setPreRule(IFlowNodePreRule preRule) {
        this.preRule = preRule;
    }

    public void setNextRule(IFlowNodeNextRule nextRule) {
        this.nextRule = nextRule;
    }

    public List<IFlowNode> getPreNodes() {
        return preNodes;
    }

    public void setPreNodes(List<IFlowNode> preNodes) {
        this.preNodes = preNodes;
    }

    public List<IFlowNode> getNextNodes() {
        return nextNodes;
    }

    public void setNextNodes(List<IFlowNode> nextNodes) {
        this.nextNodes = nextNodes;
    }

    public FlowInstance getFlowInstance() {
        return flowInstance;
    }

    public void setFlowInstance(FlowInstance flowInstance) {
        this.flowInstance = flowInstance;
    }

    public FlowNodeObject getFlowNodeObject() {
        return flowNodeObject;
    }

    public void setFlowNodeObject(FlowNodeObject flowNodeObject) {
        this.flowNodeObject = flowNodeObject;
    }
}
